<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>网页布局</title>
</head>
<style>
    h1,
    h2,
    h3,
    h4,
    h5,
    h6 {
        color: brown;
    }

    table,
    tr,
    td {
        border: 1px solid black;
    }

    table {
        margin: 0 auto;
    }

    td {
        padding: 5px;
    }

    p {
        text-indent: 2em;
    }

    img {
        display: block;
        margin: auto;
        max-width: 80%;
    }

    em {
        color: brown;
    }

    .layoutroot {
        width: 70%;
        margin: 0 auto;
    }
</style>

<body>
    <h1>网页布局</h1>
    <h2>网页布局的概念</h2>
    <p>网页布局，也就是layout，就是网页分几个板块，怎么排。
        比如，一个网页有顶栏，左栏，右栏，中间内容区域，和底栏，等。
    </p>
    <table style="border: 1px solid black;">
        <tr>
            <td>意图</td>
            <td>标签</td>
        </tr>
        <tr>
            <td>顶栏</td>
            <td>header</td>
        </tr>
        <tr>
            <td>菜单栏</td>
            <td>nav</td>
        </tr>
        <tr>
            <td>左边栏</td>
            <td>aside class="leftside"</td>
        </tr>
        <tr>
            <td>右边栏</td>
            <td>aside class="rightside"</td>
        </tr>
        <tr>
            <td>内容区</td>
            <td>main</td>
        </tr>
        <tr>
            <td>底栏</td>
            <td>footer</td>
        </tr>
    </table>
    <p>下面再考虑栏内的布局，比如main吧，我们在里面放独立的文章，可以好多篇，
        每篇一个article；每篇文章也可以有header和footer
        然后文章需要分成好几部分，我们可以用section，每个section可以有标题h1-h6。
        每个部分里面还可能有图表figure，图表可以有标题figurecaption。
    </p>
    <table>
        <tr>
            <td>标签</td>
            <td>语义</td>
            <td>典型用法</td>
        </tr>
        <tr>
            <td>article</td>
            <td>独立的、完整的相关内容块，会有header，可能有footer</td>
            <td>一篇博客、一个用户评论</td>
        </tr>
        <tr>
            <td>section</td>
            <td>文档或应用的一部分，通常有标题h1-h6</td>
            <td>章、节、对话框的一个标签页</td>
        </tr>
    </table>
    <p>好吧，明白了上述的架构，我们就可以抽象出一个基本布局模型，如下图所示：</p>
    <img src="image/basic layout model.PNG">
    <p>上图的基本模型，提示了一种用html5标签语义和布局相关联的方法。实际的应用中，
        布局按照需求，是千变万化的。很多人布局用div标签，而不使用上图所示的各种标签。
        总之html5预定义了这些标签，但是这些标签你怎么用，代表什么，也就是它的语义，
        html5做了推荐，但是并不强制。因此上述基本模型只是若干可能的选择之一。
    </p>
    <h2>布局方式</h2>
    <p>除基本布局模型外，还有好多其他的布局方式，我们都来看一下。</p>
    <h3>1 单列布局</h3>
    <p>单列布局就是从上往下排，基本不用进行专门的设置，所以也叫做自然布局。</p>
    <div class="layoutroot" style="height: 10em;">
        <header style="background-color:blanchedalmond;">header</header>
        <nav style="background-color:lightblue;">nav</nav>
        <aside class="leftaside" style="background-color: lightgreen;">aside class="leftaside"</aside>
        <aside class="rightaside" style="background-color:lightgreen;">aside class="rightaside"</aside>
        <main style="background-color:lightsalmon;">main</main>
        <footer style="background-color: mediumaquamarine;">footer</footer>
    </div>
    <p>请使用浏览器开发者工具查看上面内容对应的代码</p>
    <h3>2 float布局</h3>
    <h4>设置边栏float和宽度</h4>
    <p>浮动布局就是让边栏float到main的两侧，然后给它们合适的宽度。</p>
    <div class="layoutroot">
        <header style="background-color:blanchedalmond;">header</header>
        <nav style="background-color:lightblue;">nav</nav>
        <aside class="leftaside" style="float:left; width:30%; background-color: rgba(144, 238, 144, 1);">aside
            class="leftaside"
        </aside>
        <aside class="rightaside" style="float: right; width:30%; background-color:rgba(144, 238, 144, 1);">aside
            class="rightaside"
        </aside>
        <main style="background-color:lightsalmon;">main</main>
        <footer style="background-color: mediumaquamarine;">footer</footer>
    </div>
    <p>请使用浏览器开发者工具查看上面内容对应的代码</p>

    <p>说明：</p>
    <ul>
        <li>由于main前面的两个边栏脱离文档流，float了，因此main上移，main的宽度仍然是父容器的宽度！</li>
        <li>main的文字，由于main和边栏的重叠，导致了main里面的文字环绕</li>
        <li><em>尝试改变您的浏览器窗口大小，当边栏变成2行时，footer也会被重叠和环绕！</em></li>
    </ul>
    <h4>footer清除浮动</h4>
    <p>我们显然不想让footer参与浮动环绕，这叫做清除浮动，
        清除浮动的元素，它绝不允许自己和浮动元素发生重叠而产生环绕，
        我们可以清除left、right或者both浮动。我们设定footer清除浮动。
    </p>
    <div class="layoutroot">
        <header style="background-color:blanchedalmond;">header</header>
        <nav style="background-color:lightblue;">nav</nav>
        <aside class="leftaside" style="float:left; width:30%; background-color: rgba(144, 238, 144, 1);">aside
            class="leftaside"
        </aside>
        <aside class="rightaside" style="float: right; width:30%; background-color:rgba(144, 238, 144, 1);">aside
            class="rightaside"
        </aside>
        <main style="background-color:lightsalmon;">main</main>
        <footer style="clear: both; background-color: mediumaquamarine;">footer</footer>
    </div>
    <p>请使用浏览器开发者工具查看上面内容对应的代码</p>
    <p>再次缩小您的浏览器宽度，你会发现，footer不会和浮动元素重叠了，
        其实它下移了，因为main很短，下移后，留出了一点空白。
    </p>
    <p>下面我们为main多添加一些内容，看看如果main栏很长，会发生什么行为。</p>
    <div class="layoutroot">
        <header style="background-color:blanchedalmond;">header</header>
        <nav style="background-color:lightblue;">nav</nav>
        <aside class="leftaside" style="float:left; width:30%; background-color: rgba(144, 238, 144, 1);">aside
            class="leftaside"
        </aside>
        <aside class="rightaside" style="float: right; width:30%; background-color:rgba(144, 238, 144, 1);">aside
            class="rightaside"
        </aside>
        <main style="background-color:lightsalmon;">main 当main栏里面的内容很多时，
            它会自动变高，这是符合我们预期的效果。但是，边栏不会跟着一起变高，而且，main栏里面的的文字，
            还发生了环绕，既然是分栏，就不应该环绕。但也许这符合你的预期，那么到此就OK了。</main>
        <footer style="clear: both; background-color: mediumaquamarine;">footer</footer>
    </div>
    <p>请使用浏览器开发者工具查看上面内容对应的代码(可以适当缩小浏览器宽度)</p>

    <h4>让main不再环绕</h4>
    <p>如果你不想产生main对边栏的环绕，有两个方法：</p>
    <ul>
        <li>边栏共占去了父节点60%的宽度，我们可以将main宽度设置为父节点的40%，然后至少设置水平margin为auto，
            使main栏居中即可；
        </li>
        <li>前面的办法，对于边栏一个大一个小无效，因为main栏是居中的。我们可以分别设置左右maigin为左右栏的宽度来达到效果。</li>
    </ul>
    下面采用第二种方法进行设置：
    <p></p>
    <div class="layoutroot">
        <header style="background-color:blanchedalmond;">header</header>
        <nav style="background-color:lightblue;">nav</nav>
        <aside class="leftaside" style="float:left; width:30%; background-color: rgba(144, 238, 144, 1);">aside
            class="leftaside"
        </aside>
        <aside class="rightaside" style="float: right; width:30%; background-color:rgba(144, 238, 144, 1);">aside
            class="rightaside"
        </aside>
        <main style="margin-left: 30%; margin-right:30%; background-color:lightsalmon;">main 当main栏里面的内容很多时，
            它会自动变高，这是符合我们预期的效果。但是，边栏不会跟着一起变高，而且，main栏里面的的文字，
            还发生了环绕，既然是分栏，就不应该环绕。但也许这符合你的预期，那么到此就OK了。</main>
        <footer style="clear: both; background-color: mediumaquamarine;">footer</footer>
    </div>
    <p>请使用浏览器开发者工具查看上面内容对应的代码(可以适当缩小浏览器宽度)</p>
    <h4>让边栏和main栏等高</h4>
    <p>目前，边栏和main栏，随着内容的增加，因为宽度固定，它会自动根据内容多少增加高度。
        对于布局来说，这很好。因为如果我们设置固定高度，那么当内容太多时，就会溢出（overflow属性可以控制溢出处理并产生bfc）。
        于是我们可以设置最小高度min-height，当不超过最小高度时，等高，超了，就自适应，该多高是多高。
    </p>
    <div class="layoutroot">
        <header style="background-color:blanchedalmond;">header</header>
        <nav style="background-color:lightblue;">nav</nav>
        <aside class="leftaside"
            style="min-height: 8em; float:left; width:30%; background-color: rgba(144, 238, 144, 1);">aside
            class="leftaside"
        </aside>
        <aside class="rightaside"
            style="min-height: 8em; float: right; width:30%; background-color:rgba(144, 238, 144, 1);">aside
            class="rightaside"
        </aside>
        <main style="min-height: 8em; margin-left: 30%; margin-right:30%; background-color:lightsalmon;">main
            当main栏里面的内容很多时，
            它会自动变高，这是符合我们预期的效果。但是，边栏不会跟着一起变高，而且，main栏里面的的文字，
            还发生了环绕，既然是分栏，就不应该环绕。但也许这符合你的预期，那么到此就OK了。</main>
        <footer style="clear: both; background-color: mediumaquamarine;">footer</footer>
    </div>
    <p>变化浏览器宽度，查看高度变化情况，嗯，现在就比较完美了。</p>
    <h3>3 绝对定位布局</h3>
    <p>如你所知，<em>设置了position为absolute的元素，会脱离文档流，产生bfc，并相对于最近的已定位祖先元素定位，
            如果没有已定位祖先元素，则相对于初始包含块定位，此时元素没有外边距，但是有border和padding。
        </em></p>
    <ul>
        <li>根元素（html）元素的包含块是一个矩形，叫做初始包含块</li>
        <li>已定位元素指position是static以外的元素</li>
        <li>一般用法是父元素position设置为relative，然后子元素设置position为absolute进行定位</li>
        <li>因为元素脱离了文档流，所以父元素的高度会塌缩</li>
    </ul>
    <p>按照上述的原理，我们设置板块的容器为relative定位，然后设置其下的板块为absolute定位，
        直接指定板块位置即可。
    </p>
    <ul>
        <li>脱离文档流，节点宽度失去了参照，会收缩，需要显式指定，例如指定为父节点的100%;</li>
        <li>为了精确知道边栏和main栏的位置，我们设置了header和nav栏的高度，
            则nav栏top为header高度，边栏和main栏的top为header和nav高度之和</li>
        <li>边栏和main栏仅设置了最小高度，它们的高度可以随内容变化而变大</li>
        <li>footer定位在父节点之下，footer相对于父容器min-height定位。但是如果边栏和main栏超出了父节点要求的最小高度，
            此时，footer会被过高的边栏或main栏穿越。在真实的页面布局中，可以让footer固定定位(fixed)，
            即做一个浮动在浏览器工作区底部的页脚（参见<a href="layoutexample/absolutelayout.html">absolute布局</a>）。
        </li>
        <li><em>缺点：</em>absolute布局，在不使用javascript动态检测边栏和main栏高度变化的情况下，
            没有办法让footer相对于边栏和main栏较高的一栏定位。
        </li>
    </ul>
    <div class="layoutroot" style="position: relative; min-height: 15em;">
        <header style="position: absolute; width:100%;height:1.5em;background-color:blanchedalmond;">header</header>
        <nav style="position:absolute; width:100%;height:1.5em;top:1.5em;background-color:lightblue;">nav</nav>
        <aside class="leftaside"
            style="position:absolute; min-height:10.5em;top:3em;left:0%;right:70%;background-color: rgba(144, 238, 144, 1);">
            aside
            class="leftaside"
        </aside>
        <aside class="rightaside"
            style="position:absolute; min-height:10.5em;top:3em;left:70%;right:0%;background-color:rgba(144, 238, 144, 1);">
            aside
            class="rightaside"
        </aside>
        <main style="position:absolute; min-height:10.5em;top:3em;left:30%;right:30%;background-color:lightsalmon;">main
            <p>中间的三栏，如果过长，超出父节点设定的最小值，
                那么，footer是不会自适应往下移动的。原因是，footer相对于父容器min-height定位，
                而父容器完全不知道这些绝对定位元素的存在，它只有预设的min-height这么高。
            </p>
        </main>
        <footer style="position: absolute; top:13.5em;width:100%;background-color: mediumaquamarine;">footer</footer>
    </div>
    <p>请适当调整浏览器宽度，以查看main栏超出footer效果</p>
    <h4>4 table-cell布局</h4>
    <p>就是把板块看成表格的单元格的布局方式。table标签设置好宽度和最小高度，各板块都是单元格，边栏和main设置最小高度，
        其他栏固定高度即可。注意，td的colspan属性可以水平合并单元格。
    </p>
    <table style="width: 70%;min-height:16em;">
        <tr>
            <td colspan="3" style="height: 2em;">header</td>
        </tr>
        <tr style="min-height: 16em;">
            <td style="width: 30%;">left</td>
            <td style="width: 40%;">main
                <p>我们可以用表格来进行布局，表格会自动变高，也不失为一种布局方法。</p>
                <p>这种方法看起来比较直观，容易上手。是在css出现之前的方法，不推荐使用。</p>
                <p>缺点是：表格嵌套难维护；改变table类标签语义；用户难复制内容；降低搜索引擎收录率。</p>
            </td>
            <td style="width: 30;">right</td>
        </tr>
        <tr>
            <td colspan="3" style="height: 2em;">footer</td>
        </tr>
    </table>

    <h4>5 flex布局</h4>
    <p>flex布局，又叫弹性布局，是较晚近出现的一种布局方法。灵活，代码少。</p>
    <div class="layoutroot" style="display:flex; flex-direction: column; min-height: 20em;">
        <header style="height:1.5em; width:100%;background-color:blanchedalmond;">header</header>
        <nav style="height:1.5em;width:100%;background-color:lightblue;">nav</nav>
        <div style="min-height: 14.5em; display: flex;flex-direction: row;">
            <aside class="leftaside" style="width:30%;background-color: lightgreen;">aside
                class="leftaside"</aside>
            <main style="width:40%;background-color:lightsalmon;">main
                <p>flex又叫弹性布局。</p>
                <p>较晚近出现的一种布局方法。灵活，代码少。</p>
                <p>header、三栏、footer三个部分是竖排的，flex-direction为column。</p>
                <p>边栏和main是横排的，flex-direction为row。注意加了一个 flex div来包含它们改变排列方向。</p>
            </main>
            <aside class="rightaside" style="width:30%;background-color:lightgreen;">aside class="rightaside"</aside>
        </div>
        <footer style="height:1.5em;width:100%;background-color: mediumaquamarine;">footer</footer>
    </div>
    <ul>
        <li>header、三栏、footer三个部分是竖排的，flex-direction为column。</li>
        <li>边栏和main是横排的，flex-direction为row。注意加了一个 flex div来包含它们以改变排列方向。</li>
    </ul>
    <h4>6 grid布局</h4>
    <p>Grid布局也很直观，在父节点上定义网格，分别用grid-template-rows和grid-template-columns。
        然后父节点就被分成了一个个的单元格了，用grid-template-area来划分区域，
        最后用子元素的grid-area属性将子元素指定到区域。直观，但是定义麻烦。
    </p>
    <div class="layoutroot" style="display:grid;min-height:20em; 
    grid-template-rows: 1.5em 1.5em auto 1.5em;
    grid-template-columns: 30% auto 30%;
    grid-template-areas: 
    'a a a'
    'b b b'
    'c d e'
    'f f f'
    ;">
        <header style="grid-area: a; background-color:blanchedalmond;">header</header>
        <nav style="grid-area:b; background-color:lightblue;">nav</nav>
        <aside class="grid-area:c;leftaside" style="background-color: lightgreen;">aside class="leftaside"</aside>
        <aside class="grid-area:e;rightaside" style="background-color:lightgreen;">aside class="rightaside"</aside>
        <main style="grid-area:d;background-color:lightsalmon;">main
            <p>Grid布局也很直观，在父节点上定义网格，分别用grid-template-rows和grid-template-columns。
        然后父节点就被分成了一个个的单元格了，用grid-template-area来划分区域，
        最后用子元素的grid-area属性将子元素指定到区域。直观，但是定义麻烦。
    </p>
        </main>
        <footer style="grid-area:f;background-color: mediumaquamarine;">footer</footer>
    </div>

    <h3>总结</h3>

    <table style="width:70%">
        <tr>
            <td style="width: 30%;">布局方法</td><td>优缺点</td>
        </tr>
        <tr>
            <td>float</td><td>简单，兼容性好；脱离文档流，高度塌陷，需要清除浮动</td>
        </tr>
        <tr>
            <td>absolute</td><td>快捷、方便；脱离文档流，当高度未知时，无法接着排，有效性和可使用性较差</td>
        </tr>
        <tr>
            <td>flex</td><td>css3新出，完美，移动端表现良好；ie10以上才支持</td>
        </tr>
        <tr>
            <td>table</td><td>兼容性好，内容溢出会自动撑开父元素；无法设置栏边距，seo不友好</td>
        </tr>
        <tr>
            <td>grid</td><td>最强大、最简单；兼容性不好，ie10+仅部分兼容</td>
        </tr>
    </table>

    <h2>参考文献</h2>
    <ul>
        <li><a href="https://blog.csdn.net/m0_38134431/article/details/84372226">https://blog.csdn.net/m0_38134431/article/details/84372226</a></li>
        <li><a href="http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html">http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html</a></li>
    </ul>
</body>



</html>